package com.wlyuan.open.scanner.repository.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wlyuan.open.scanner.dao.entity.BalanceBillindexDO;
import com.wlyuan.open.scanner.dao.entity.FinanceBillDO;
import com.wlyuan.open.scanner.dao.mapper.BalanceBillindexMapper;
import com.wlyuan.open.scanner.dao.mapper.FinanceBillMapper;
import com.wlyuan.open.scanner.dao.write.FinanceBillWriteMapper;
import com.wlyuan.open.scanner.domain.finance.relation.Finance;
import com.wlyuan.open.scanner.domain.finance.relation.FinanceConvert;
import com.wlyuan.open.scanner.repository.FinanceBillRepository;
import com.wlyuan.open.scanner.utils.enums.bill.BillStatusEnum;
import com.wlyuan.open.scanner.utils.enums.bill.BillTypeEnum;
import com.wlyuan.open.utils.LongUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lijing
 * @description
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class FinanceBillRepositoryImpl implements FinanceBillRepository {
    private final FinanceBillMapper financeBillMapper;
    private final FinanceBillWriteMapper financeBillWriteMapper;
    private final BalanceBillindexMapper balanceBillindexMapper;

    @Override
    public Finance getByUpOrDown(Long sourceId) {
        var data = financeBillMapper.getByUpOrDown(sourceId);
        return FinanceConvert.convert(data);
    }

    @Override
    public List<Long> getTime(String startTime, String endTime) {
        LambdaQueryWrapper<BalanceBillindexDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(BalanceBillindexDO::getIndexInserttime, startTime).le(BalanceBillindexDO::getIndexInserttime, endTime).in(BalanceBillindexDO::getIndexStatus, Arrays.asList(0, 1, 2, 4, 8));
        var list = balanceBillindexMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        //对账单id
        var ids = list.parallelStream().map(BalanceBillindexDO::getIndexId).collect(Collectors.toList());
        //去重
        var data = ids.parallelStream().map(this::getByUpOrDown).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        return data.parallelStream().map(d -> {
            return d.getUp() > 0 ? d.getUp() : d.getDown();
        }).collect(Collectors.toList());
    }

    @Override
    public List<Long> getTenantIdTime(Long tenantId, String startTime, String endTime) {
        LambdaQueryWrapper<BalanceBillindexDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BalanceBillindexDO::getIndexOwnercompanyid, tenantId).ge(BalanceBillindexDO::getIndexInserttime, startTime).le(BalanceBillindexDO::getIndexInserttime, endTime).in(BalanceBillindexDO::getIndexStatus, Arrays.asList(0, 1, 2, 4, 8));
        var list = balanceBillindexMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        //对账单id
        var ids = list.parallelStream().map(BalanceBillindexDO::getIndexId).collect(Collectors.toList());
        //去重
        var data = ids.parallelStream().map(this::getByUpOrDown).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        return data.parallelStream().map(d -> {
            return d.getUp() > 0 ? d.getUp() : d.getDown();
        }).collect(Collectors.toList());
    }

    @Override
    public void save(Long billId, Integer billType, Long tenantId, Long srcId) {
        LambdaQueryWrapper<FinanceBillDO> queryWrapper = new LambdaQueryWrapper<>();
        if (BillTypeEnum.RECEIVABLE.getValue().equals(billType)) {
            queryWrapper.eq(FinanceBillDO::getDown, billId);
        }
        if (BillTypeEnum.PAYABLE.getValue().equals(billType)) {
            queryWrapper.eq(FinanceBillDO::getUp, billId);
        }
        var data = financeBillMapper.selectOne(queryWrapper);
        Optional.ofNullable(assemble(billId, billType, tenantId, srcId)).ifPresent(bill -> {
            if (Optional.ofNullable(data).isPresent()) {
                bill.setId(data.getId());
                bill.setUpdateTime(LocalDateTime.now());
                financeBillWriteMapper.updateById(bill);
            } else {
                bill.setCreateTime(LocalDateTime.now());
                financeBillWriteMapper.insert(bill);
            }
        });
    }

    @Override
    public void init() {
        logger.info("truncate");
        financeBillWriteMapper.truncate();
        logger.info("insert");
        financeBillWriteMapper.init();
        logger.info("初始化完成");
    }

    @Override
    public void initTime(String startTime, String endTime) {
        logger.info("insert");
        financeBillWriteMapper.initTime(startTime, endTime);
        logger.info("初始化完成");
    }

    private FinanceBillDO assemble(Long billId, Integer billType, Long tenantId, Long srcId) {
        //应收
        if (BillTypeEnum.RECEIVABLE.getValue().equals(billType)) {
            return receivable(billId, srcId, tenantId);
        }
        //应付
        if (BillTypeEnum.PAYABLE.getValue().equals(billType)) {
            return payable(billId, srcId, tenantId);
        }
        return null;
    }

    private FinanceBillDO receivable(Long billId, Long srcId, Long tenantId) {
        FinanceBillDO finance = new FinanceBillDO();
        finance.setTenantId(tenantId);
        finance.setDown(billId);
        if (LongUtils.notNullLong(srcId)) {
            finance.setUp(srcId);
            finance.setTenantId(balanceBillindexMapper.getById(srcId).getIndexOwnercompanyid());
        } else {
            var up = getRelationBill(billId);
            finance.setUp(up);
        }
        return finance;
    }

    private FinanceBillDO payable(Long billId, Long srcId, Long tenantId) {
        FinanceBillDO finance = new FinanceBillDO();
        finance.setTenantId(tenantId);
        finance.setUp(billId);
        if (LongUtils.notNullLong(srcId)) {
            finance.setDown(srcId);
        } else {
            var down = getRelationBill(billId);
            finance.setDown(down);
        }
        return finance;
    }

    private Long getRelationBill(Long billId) {
        LambdaQueryWrapper<BalanceBillindexDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BalanceBillindexDO::getIndexSrcid, billId)
                .in(BalanceBillindexDO::getIndexStatus, Arrays.asList(BillStatusEnum.ALREADY_CHECK.getValue(),
                        BillStatusEnum.ALREADY_CHECKOUT.getValue(), BillStatusEnum.ALREADY_BILL.getValue()));
        var list = balanceBillindexMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return 0L;
        }
        return list.stream().findFirst().get().getIndexId();
    }
}
